#include <iostream>
#include <vector>
#include <concepts>     // 显式包含，提高代码可读性
#include <type_traits>  // 如果直接使用 is_integral_v

// 测试环境
// ~/l/g/cpp_learn_template_srsj on master ❯ g++ --version                               at 09:47:21
// Apple clang version 16.0.0 (clang-1600.0.26.6)
// Target: arm64-apple-darwin24.6.0
// Thread model: posix
// InstalledDir: /Library/Developer/CommandLineTools/usr/bin

// 在 C++20 之前，我们通常使用 ​SFINAE​ 等技术来约束模板参数，但这种方式编写复杂、可读性差，并且出错时编译器给出的信息非常难以理解

// ​Concepts 的本质是一种作用于编译期的类型约束，它明确声明了模板参数必须满足的条件，可以理解为类型必须实现的“编译期接口”

// 定义一个conncepts：使用 concept关键字来定义，通常在 requires表达式中列出类型 T必须满足的条件

// 定义一个要求类型 T 必须具有 size() 成员函数，且返回值可转换为 size_t 的 Concept
template<typename T>
concept HasSize = requires(T t) {
    { t.size() } -> std::convertible_to<std::size_t>;
};

// 定义一个要求类型 T 必须是整数类型的概念
template<typename T>
concept Integral = std::is_integral_v<T>;


//使用 Concepts 约束模板

template <HasSize Container> // Container 必须满足 HasSize 概念
void printSize(const Container& c) {
    std::cout << c.size() << std::endl;
}

template <typename Container>
requires HasSize<Container> // requires 子句
void printSize2(const Container& c) {
    std::cout << c.size() << std::endl;
}

// 将 requires 子句放在后面
template <typename Container>
void printSize3(const Container& c) requires HasSize<Container> {
    std::cout << c.size() << std::endl;
}

void printSize4(HasSize auto& c) {
    std::cout << c.size() << std::endl;
}

int main(){
    std::cout<<"run in main fun--concepts_test_251010.cpp"<<std::endl;

    std::vector<int> vtInt {1,2,3,7};
    printSize(vtInt);    
    printSize2(vtInt);    
    printSize3(vtInt);    
    printSize4(vtInt);    
    return 0;
}


template<typename T>
T add_old(T a, T b) {
    return a + b;
}

#include <concepts>

template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::same_as<T>;  // 要求类型T支持加法操作
};

template<Addable T>
T add_new(T a, T b) {
    return a + b;
}


// 晦涩的错误信息
void testCrypticErrorMessageTemplate(){
    //add_old("abc", "def");
//     /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:60:14:
//  error: invalid operands to binary expression ('const char *' and 'const char *')
//    60 |     return a + b;
//       |            ~ ^ ~
// /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:66:5: note:
//  in instantiation of function template specialization 'add_old<const char *>' requested here
//    66 |     add_old("abc", "def");

    //add_new("abc", "def");
// /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:87:5:
//  error: no matching function for call to 'add_new'
//    87 |     add_new("abc", "def");
//       |     ^~~~~~~
// /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:71:3:
//  note: candidate template ignored: constraints not satisfied [with T = const char *]
//    71 | T add_new(T a, T b) {
//       |   ^
// /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:70:10:
//  note: because 'const char *' does not satisfy 'Addable'
//    70 | template<Addable T>
//       |          ^
// /Users/xiarunliang/learn/giteRep/cpp_learn_template_srsj/template-cpp-learn/concepts_test_251010.cpp:67:9:
//  note: because 'a + b' would be invalid: invalid operands to binary expression ('const char *' and 'const char *')
//    67 |     { a + b } -> std::same_as<T>;  // 要求类型T支持加法操作
}

